package calculation

import (
	"errors"

	"github.com/shopspring/decimal"
	models "gitverse.ru/z3nyk3y/investcalc/internal/models"
)

var ErrInvalidTask = errors.New("invalid task")
var ErrOperationNotSupportedYet = errors.New("operation not supported yet")

type UseCase struct {
	calc *models.Calculator
}

func NewUseCase(calc *models.Calculator) *UseCase {
	return &UseCase{calc}
}

func (uc *UseCase) Calc() (decimal.Decimal, error) {
	switch uc.calc.ToCalculate {
	case models.TARGET:
		return uc.calcTarget(), nil
	case models.START_UP_CAPITAL:
		// return decimal.Zero, ErrOperationNotSupportedYet
		return uc.calcStartUpCapital(), nil
	case models.INVEST_PERIOD:
		return decimal.Zero, ErrOperationNotSupportedYet
		// return c.calcInvestPeriod()
	case models.COEFFICIENT:
		return decimal.Zero, ErrOperationNotSupportedYet
		// return c.calcCoefficient()
	case models.ADDICTIONAL_INVESTMENT:
		return decimal.Zero, ErrOperationNotSupportedYet
		// return c.calcAddictionalInvestment()
	}
	return decimal.Zero, ErrInvalidTask
}

func (uc *UseCase) calcTarget() decimal.Decimal {
	var ans decimal.Decimal
	coef := uc.calc.Coefficient.Div(decimal.NewFromInt32(100))

	if uc.calc.ReinvestPeriod == models.NEVER {
		a := uc.calc.StartUpCapital
		b := decimal.Sum(decimal.NewFromInt32(1), uc.calc.Coefficient.Mul(uc.decimalInvestPeriodInYear()))
		ans = a.Mul(b)

	} else {
		a := decimal.Sum(decimal.NewFromInt32(1), coef.Div(uc.ReinvestPeriodTimesPerYears())).Pow(uc.ReinvestPeriodTimesPerYears().Mul(uc.decimalInvestPeriodInYear()))
		ans = uc.calc.StartUpCapital.Mul(a)
	}

	return ans
}

func (uc *UseCase) calcStartUpCapital() decimal.Decimal {
	var ans decimal.Decimal
	coef := uc.calc.Coefficient.Div(decimal.NewFromInt32(100))

	if uc.calc.ReinvestPeriod == models.NEVER {
		a := uc.calc.Target
		b := decimal.Sum(decimal.NewFromInt32(1), uc.calc.Coefficient.Mul(uc.decimalInvestPeriodInYear()))
		ans = a.Div(b)

	} else {
		a := decimal.Sum(decimal.NewFromInt32(1), coef.Div(uc.ReinvestPeriodTimesPerYears())).Pow(uc.ReinvestPeriodTimesPerYears().Mul(uc.decimalInvestPeriodInYear()))
		ans = uc.calc.Target.Div(a)
	}

	return ans
}

func (uc *UseCase) decimalInvestPeriodInYear() decimal.Decimal {
	switch uc.calc.InvestPeriod.Period {
	case models.YEARS:
		return decimal.NewFromInt32(int32(uc.calc.InvestPeriod.Amount))
	case models.MONTHS:
		return decimal.NewFromInt32(int32(uc.calc.InvestPeriod.Amount)).Div(decimal.NewFromInt32(12))
	default:
		return decimal.Zero
	}

}

func (uc *UseCase) ReinvestPeriodTimesPerYears() decimal.Decimal {
	switch uc.calc.ReinvestPeriod {
	case models.MONTHLY:
		return decimal.NewFromInt32(12)
	case models.QUARTERLY:
		return decimal.NewFromInt32(4)
	case models.TWICE_A_YEAR:
		return decimal.NewFromInt32(2)
	case models.YEARLY:
		return decimal.NewFromInt32(1)
	default:
		return decimal.Zero

	}
}
